package com.gitee.feizns.dynamic;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * <b>{@link List}操作工具类</b>
 * @author feizns
 * @since 2023/3/14
 */
public abstract class Lists {

    /**
     * <b>将list切割为每size一份</b>
     * <pre>{@code
     *  List<User> users = userRepository.findAll();
     *  //按每50个一组分割
     *  List<List<User>> parts = ListUtils.partition(users, 50);
     *  parts.stream().forEach(list -> {
     *     process(list);
     *  });
     * }</pre>
     * @param list {@link List}
     * @param size 切割大小
     * @return 切割后的每份集合
     * @param <T> 元素类型
     */
    public static <T> List<List<T>> partition(List<T> list, int size) {
        int listSize = list.size();
        int stepSize = listSize % size == 0 ? listSize / size : (listSize / size) + 1;
        List<List<T>> resultList = new ArrayList<>();
        for (int i = 0; i < stepSize; i++) {
            int fromIndex = i * size;
            int endIndex = (i + 1) * size;
            if (endIndex > listSize)
                endIndex = listSize;
            resultList.add(list.subList(fromIndex, endIndex));
        }
        return resultList;
    }

    /**
     * 所有元素
     * @param elements 元素
     * @return {@link List }<{@link T }>
     */
    @SafeVarargs
    @SuppressWarnings("unchecked")
    public static <T> T[] toArray(T... elements) {
        return (T[]) of(elements).toArray();
    }

    /**
     * 所有元素
     * @param arrays 数组列表
     * @return {@link List}<{@link T}>
     */
    @SafeVarargs
    @SuppressWarnings("unchecked")
    public static <T> T[] toArray(T[]... arrays) {
        return (T[]) of(arrays).toArray();
    }

    /**
     * 所有元素
     * @param iterators 迭代器
     * @return {@link T[]}
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] toArray(Iterator<T>... iterators) {
        return (T[]) of(iterators).toArray();
    }

    /**
     * 所有元素
     * @param iterables 可迭代对象
     * @return {@link T[]}
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] toArray(Iterable<T>... iterables) {
        return (T[]) of(iterables).toArray();
    }

    /**
     * 所有元素
     * @param elements 元素
     * @return {@link List }<{@link T }>
     */
    @SafeVarargs
    public static <T> List<T> of(T... elements) {
        return of(ArrayList::new, elements);
    }

    /**
     * 所有元素
     * @param arrays 数组列表
     * @return {@link List}<{@link T}>
     */
    @SafeVarargs
    public static <T> List<T> of(T[]... arrays) {
        return of(ArrayList::new, arrays);
    }

    /**
     * 所有元素
     * @param iterators 迭代器
     * @return {@link List }<{@link T }>
     */
    @SafeVarargs
    public static <T> List<T> of(Iterator<T>... iterators) {
        return of(ArrayList::new, iterators);
    }

    /**
     * 所有元素
     * @param iterables 可迭代对象
     * @return {@link List}<{@link T}>
     */
    @SafeVarargs
    public static <T> List<T> of(Iterable<T>... iterables) {
        return of(ArrayList::new, iterables);
    }

    /**
     * 自定义list将元素添加到list中
     * @param arrays 元素
     * @return {@link List }<{@link T }>
     */
    @SafeVarargs
    public static <T> List<T> of(Supplier<List<T>> listSupplier, T[]... arrays) {
        List<T> ts = listSupplier.get();
        for (T[] array : arrays)
            ts.addAll(Arrays.asList(array));
        return ts;
    }

    /**
     * 自定义list将元素添加到list中
     * @param listSupplier 列表供应商
     * @param iterators 迭代器
     * @return {@link List}<{@link T}>
     */
    @SafeVarargs
    public static <T> List<T> of(Supplier<List<T>> listSupplier, Iterator<T>... iterators) {
        List<T> ts = listSupplier.get();
        for (Iterator<T> iterator : iterators) {
            while ( iterator.hasNext() )
                ts.add(iterator.next());
        }
        return ts;
    }

    /**
     * 自定义list将元素添加到list中
     * @param listSupplier 列表供应商
     * @param iterables 可迭代对象
     * @return {@link List}<{@link T}>
     */
    @SafeVarargs
    public static <T> List<T> of(Supplier<List<T>> listSupplier, Iterable<T>... iterables) {
        List<T> ts = listSupplier.get();
        for (Iterable<T> iterable : iterables) {
            for (T t: iterable)
                ts.add(t);
        }
        return ts;
    }

    /**
     * 在容器中查找匹配条件元素的位置
     * @param iterable {@link Iterable}
     * @param test {@link Predicate}
     * @param <T> 集合类型
     * @return 匹配条件的第一个下标
     */
    public static <T> int indexOf(Predicate<T> test, Iterable<T> iterable) {
        return iterable != null ? indexOf(test, iterable.iterator()) : -1;
    }

    /**
     * 迭代器查询匹配条件元素的位置
     * @param iterator {@link Iterator}
     * @param test 测试条件
     * @param <T> 元素
     * @return 是否包含
     */
    public static <T> int indexOf(Predicate<T> test, Iterator<T> iterator) {
        int index = 0;
        while( iterator.hasNext() ) {
            if (test.test(iterator.next()))
                return index;
            index++;
        }
        return -1;
    }

    /**
     * <b>查找第一个元素的下标</b>
     * @param test 查找的判断条件
     * @param array 数组
     * @return array中第一个匹配test规则的元素下标
     */
    @SafeVarargs
    public static <T> int indexOf(Predicate<T> test, T... array) {
        if ( array != null ) {
            for (int i = 0; i < array.length; i++) {
                if ( test.test(array[i]) )
                    return i;
            }
        }
        return -1;
    }

    /**
     * 在容器中查找匹配条件元素的位置
     * @param iterable {@link Iterable}
     * @param test {@link Predicate}
     * @param <T> 集合类型
     * @return 匹配条件的第一个下标
     */
    public static <T> int lastIndexOf(Predicate<T> test, Iterable<T> iterable) {
        return iterable != null ? lastIndexOf(test, iterable.iterator()) : -1;
    }

    /**
     * 迭代器查询匹配条件元素的位置
     * @param iterator {@link Iterator}
     * @param test 测试条件
     * @param <T> 元素
     * @return 是否包含
     */
    public static <T> int lastIndexOf(Predicate<T> test, Iterator<T> iterator) {
        if ( iterator != null ) {
            List<T> ts = of(iterator);
            for (int i = ts.size() - 1; i > -1; i--) {
                if ( test.test(ts.get(i)) )
                    return i;
            }
        }
        return -1;
    }

    /**
     * <b>查找第一个元素的下标</b>
     * @param test 查找的判断条件
     * @param array 数组
     * @return array中第一个匹配test规则的元素下标
     */
    @SafeVarargs
    public static <T> int lastIndexOf(Predicate<T> test, T... array) {
        if ( array != null ) {
            for (int i = array.length - 1; i > -1; i--) {
                if ( test.test(array[i]) )
                    return i;
            }
        }
        return -1;
    }

    /**
     * 获取数组中元素
     * @param array 数组
     * @return 返回数组中指定位置的数据，不存在返回null
     */
    public static <T> T get(T[] array, int index) {
        return Ex.tryCatch(() -> array[index]).ignoreException(IndexOutOfBoundsException.class).orElse(null);
    }

    /**
     * 获取迭代器中元素
     * @param iterable 可迭代
     * @param index 指数
     * @return 返回迭代器中位置的元素
     */
    public static <T> T get(Iterable<T> iterable, int index) {
        return get(iterable.iterator(), index);
    }

    /**
     * 获取迭代器中元素
     * @param iterator {@link Iterator}
     * @return 返回迭代器中位置的元素
     * @param <T> 元素类型
     */
    public static <T> T get(Iterator<T> iterator, int index) {
        //noinspection unchecked
        return get(toArray(iterator), index);
    }

    /**
     * 获取数组中第一个元素
     * @param array 数组
     * @return 返回迭代器中位置第一的元素
     */
    public static <T> T first(T[] array) {
        return array != null ? array[0] : null;
    }

    /**
     * 获取迭代器中第一个元素
     * @param iterable 可迭代
     * @return 返回迭代器中位置第一的元素
     */
    public static <T> T first(Iterable<T> iterable) {
        return first(iterable.iterator());
    }

    /**
     * 获取迭代器中第一个元素
     * @param iterator {@link Iterator}
     * @return 返回迭代器中位置第一的元素
     * @param <T> 元素类型
     */
    public static <T> T first(Iterator<T> iterator) {
        return iterator.hasNext() ? iterator.next() : null;
    }

    /**
     * 获取迭代器中最后一个元素
     * @param iterable 可迭代
     * @return 返回迭代器中最后一个元素
     */
    public static <T> T last(Iterable<T> iterable) {
        return last(iterable.iterator());
    }

    /**
     * 获取迭代器中最后一个元素
     * @param iterator {@link Iterator}
     * @return 返回迭代器中最后一个元素
     * @param <T> 元素类型
     */
    public static <T> T last(Iterator<T> iterator) {
        T ret = null;
        while( iterator.hasNext() )
            ret = iterator.next();
        return ret;
    }

    /**
     * <b>将数组包装成{@code Iterator}</b>
     * @see Iterator
     * @param ele 数组元素
     * @param <T> 数组元素类型
     * @return 返回包含ele中所有元素的迭代器
     */
    @SafeVarargs
    public static <T> Iterator<T> iterator(T... ele) {
        return ele != null ? java.util.Arrays.stream(ele).iterator() : Collections.emptyIterator();
    }

    /**
     * <b>将数组包装成{@code Iterable}</b>
     * @see Iterable
     * @param ele 数组元素
     * @param <T> 数组元素类型
     * @return 返回包含ele中所有元素的迭代器
     */
    @SafeVarargs
    public static <T> Iterable<T> iterable(T... ele) {
        return () -> iterator(ele);
    }

}
